# 1. 安装Tushare库（首次运行需执行，后续不用） 
# pip install tushare -i https://pypi.tuna.tsinghua.edu.cn/simple
# pip install backtrader -i https://pypi.tuna.tsinghua.edu.cn/simple
# 63defece641436396989405961579b92948c7f5598523913b3754e6a

import tushare as ts
import pandas as pd
import matplotlib.pyplot as plt


ts.set_token("63defece641436396989405961579b92948c7f5598523913b3754e6a")
pro = ts.pro_api()

# 4. 获取贵州茅台（600519.SH）2020-2023年日线数据
df = pro.daily(
    ts_code="600519.SH",  # 股票代码（A股格式：6位代码+.[SH/SZ]，SH=沪市，SZ=深市）
    start_date="20240101",  # 开始日期（格式：YYYYMMDD）
    end_date="20251231"     # 结束日期
)

# 5. 数据预处理（按日期排序，确保时间顺序正确）
df["trade_date"] = pd.to_datetime(df["trade_date"], format="%Y%m%d")  # 把字符串日期转成日期格式
df = df.sort_values("trade_date").reset_index(drop=True)  # 按日期升序排序

# 6. 查看数据（前5行，确认是否获取成功）
# print(df[["trade_date", "open", "high", "low", "close", "vol"]].head())

# 7. 保存数据到本地（可选，后续复用）
# df.to_csv("贵州茅台日线数据2020-2023.csv", index=False, encoding="utf-8")




# 1. 计算MA5和MA20（基于收盘价）
df["MA5"] = df["close"].rolling(window=5).mean()  # 5日移动平均
df["MA20"] = df["close"].rolling(window=20).mean()  # 20日移动平均

# 2. 生成买卖信号（1=买入，-1=卖出，0=无操作）
df["signal"] = 0  # 初始化信号为0

# 买入信号：MA5上穿MA20（前一天MA5<MA20，当天MA5>=MA20）
df.loc[(df["MA5"] >= df["MA20"]) & (df["MA5"].shift(1) < df["MA20"].shift(1)), "signal"] = 1

# 卖出信号：MA5下穿MA20（前一天MA5>MA20，当天MA5<=MA20）
df.loc[(df["MA5"] <= df["MA20"]) & (df["MA5"].shift(1) > df["MA20"].shift(1)), "signal"] = -1

# 3. 查看信号（筛选出有买卖信号的行，确认逻辑是否正确）
signal_df = df[df["signal"] != 0][["trade_date", "close", "MA5", "MA20", "signal"]]
print("买卖信号汇总：")
print(signal_df.head(10))

# 4. 可视化均线和信号（直观看到金叉/死叉）
plt.rcParams["font.sans-serif"] = ["SimHei"]  # 解决中文显示问题
plt.figure(figsize=(12, 6))  # 设置图表大小

# 绘制收盘价、MA5、MA20
plt.plot(df["trade_date"], df["close"], label="收盘价", color="blue", alpha=0.6)
plt.plot(df["trade_date"], df["MA5"], label="MA5（5日均线）", color="red", linewidth=2)
plt.plot(df["trade_date"], df["MA20"], label="MA20（20日均线）", color="green", linewidth=2)

# 标记买入信号（红色上箭头）和卖出信号（绿色下箭头）
buy_signals = df[df["signal"] == 1]
sell_signals = df[df["signal"] == -1]
plt.scatter(buy_signals["trade_date"], buy_signals["close"], marker="^", color="red", s=100, label="买入")
plt.scatter(sell_signals["trade_date"], sell_signals["close"], marker="v", color="green", s=100, label="卖出")

# 设置图表标签和图例
plt.xlabel("日期", fontsize=12)
plt.ylabel("价格（元）", fontsize=12)
plt.title("贵州茅台双均线策略（2020-2023）", fontsize=14)
plt.legend()
plt.grid(alpha=0.3)
plt.show()


# 1. 计算持仓状态（1=持有，0=空仓）
df["position"] = 0  # 初始化持仓为0
for i in range(1, len(df)):
    # 若前一天有买入信号，当天开始持仓
    if df["signal"].iloc[i-1] == 1:
        df["position"].iloc[i] = 1
    # 若前一天有卖出信号，当天开始空仓
    elif df["signal"].iloc[i-1] == -1:
        df["position"].iloc[i] = 0
    # 若无信号，保持前一天的持仓状态
    else:
        df["position"].iloc[i] = df["position"].iloc[i-1]

# 2. 计算策略收益（按日计算，持仓时赚收盘价涨跌幅，空仓时收益为0）
df["daily_return"] = df["close"].pct_change()  # 每日收盘价涨跌幅（%）
df["strategy_return"] = df["position"] * df["daily_return"]  # 策略每日收益

# 3. 计算累计收益（总收益）
df["cumulative_market"] = (1 + df["daily_return"]).cumprod()  # 市场累计收益（买了不动）
df["cumulative_strategy"] = (1 + df["strategy_return"]).cumprod()  # 策略累计收益

# 4. 输出关键回测指标（评估策略好坏）
total_days = len(df)
total_strategy_return = (df["cumulative_strategy"].iloc[-1] - 1) * 100  # 总收益（%）
total_market_return = (df["cumulative_market"].iloc[-1] - 1) * 100  # 市场总收益（%）
annual_return = total_strategy_return / (total_days / 250)  # 年化收益（假设一年250个交易日）

print("回测结果（2020-2023年）：")
print(f"策略总收益：{total_strategy_return:.2f}%")
print(f"市场总收益（买入不动）：{total_market_return:.2f}%")
print(f"策略年化收益：{annual_return:.2f}%")

# 5. 可视化累计收益（对比策略和市场）
# plt.figure(figsize=(12, 6))
# plt.plot(df["trade_date"], df["cumulative_market"], label="市场收益（买入不动）", color="blue", alpha=0.6)
# plt.plot(df["trade_date"], df["cumulative_strategy"], label="双均线策略收益", color="red", linewidth=2)
# plt.xlabel("日期", fontsize=12)
# plt.ylabel("累计收益（初始本金=1）", fontsize=12)
# plt.title("贵州茅台双均线策略 vs 市场收益（2020-2023）", fontsize=14)
# plt.legend()
# plt.grid(alpha=0.3)
# plt.show()

# 计算每笔交易的成本（佣金+印花税）
df["trade_cost"] = 0
# 卖出时：印花税0.1% + 佣金0.03%
df.loc[df["signal"] == -1, "trade_cost"] = - (df["close"] * 0.001 + df["close"] * 0.0003)
# 买入时：佣金0.03%（最低5元，这里简化按比例算）
df.loc[df["signal"] == 1, "trade_cost"] = - df["close"] * 0.0003

# 重新计算策略收益（加入成本）
df["strategy_return_with_cost"] = df["position"] * df["daily_return"] + (df["trade_cost"] / df["close"].shift(1))
df["cumulative_strategy_with_cost"] = (1 + df["strategy_return_with_cost"]).cumprod()

# 重新计算总收益
total_strategy_return_with_cost = (df["cumulative_strategy_with_cost"].iloc[-1] - 1) * 100
print(f"加入交易成本后，策略总收益：{total_strategy_return_with_cost:.2f}%")


# 样本内：2020-2022年（用于优化策略）
df_in = df[df["trade_date"] <= "20241231"]
# 样本外：2023年（用于验证策略）
df_out = df[df["trade_date"] > "20241231"]

# 计算样本外策略收益
df_out["strategy_return_out"] = df_out["position"] * df_out["daily_return"]
df_out["cumulative_strategy_out"] = (1 + df_out["strategy_return_out"]).cumprod()

# 输出样本外结果
total_out_return = (df_out["cumulative_strategy_out"].iloc[-1] - 1) * 100
print(f"样本外（2023年）策略总收益：{total_out_return:.2f}%")